import abc
import os.path

from classpath.class_entry import CompositeEntry, ZipEntry, DirEntry, ClassEntry, ClassBytes
from consts.common import JAR_FILE_SUFFIX, ZIP_FILE_SUFFIX, PATH_LIST_SEPARATOR, ANY_MATCH_CHAR


class ClassPath:
    def newWildCardEntry(self, path) -> ClassEntry:
        baseDir = path[:len(path) - 2]
        entry = CompositeEntry()
        for file in os.listdir(path=baseDir):
            all_path = "{}/{}".format(baseDir, file)
            if os.path.isdir(all_path) and all_path != baseDir:
                continue
            if JAR_FILE_SUFFIX in file or ZIP_FILE_SUFFIX in file:
                jarEntry = ZipEntry(absDir=all_path)
                entry.append(jarEntry)
            elif os.path.isdir(all_path):
                dirEntry = DirEntry(absDir=all_path)
                entry.append(dirEntry)
        return entry

    def newEntry(self, path: str) -> ClassEntry:
        if PATH_LIST_SEPARATOR in path:
            return self.newWildCardEntry(path)
        elif path.endswith(ANY_MATCH_CHAR):
            return self.newWildCardEntry(path)
        elif path.endswith(JAR_FILE_SUFFIX.lower()) or path.endswith(
                JAR_FILE_SUFFIX.upper()) or path.endswith(
            ZIP_FILE_SUFFIX.lower()) or path.endswith(ZIP_FILE_SUFFIX.upper()):
            return ZipEntry(absDir=path)
        else:
            return DirEntry(absDir=path)

    def toClassFilePath(self,className):
        return "{}.class".format(className.replace(".","/"))

    @abc.abstractmethod
    def readClass(self, className: str)->ClassBytes:
        pass


class BootStrapClassPath(ClassPath):
    def __init__(self, jreOption: str):
        self.jreOption = jreOption
        self.path = os.path.join(jreOption, "lib", "*")
        self.bootstrapEntry = self.newWildCardEntry(path=self.path)

    def readClass(self, className: str)->ClassBytes:
       return self.bootstrapEntry.ReadClass(className=self.toClassFilePath(className=className))


class ExtClassPath(ClassPath):
    def __init__(self, jreOption: str):
        self.jreOption = jreOption
        self.path = os.path.join(jreOption,"lib", "ext", "*")
        self.extEntry = self.newWildCardEntry(path=self.path)

    def readClass(self, className: str)->ClassBytes:
        return self.extEntry.ReadClass(className=self.toClassFilePath(className=className))


class ApplicationClassPath(ClassPath):
    def __init__(self, cpOption: str):
        self.cpOption = cpOption
        self.path = cpOption
        self.appEntry = self.newEntry(path=self.path)

    def readClass(self, className: str)->ClassBytes:
        return self.appEntry.ReadClass(className=self.toClassFilePath(className=className))
